package com.devshephard.rpcframework.rpc.factory.channel;
import com.devshephard.rpcframework.rpc.handler.RpcResponseMessageHandler;
import com.devshephard.rpcframework.rpc.protocol.MessageCodecSharable;
import com.devshephard.rpcframework.rpc.protocol.ProcotolFrameDecoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * Netty Channel单例工厂
 */
@Slf4j
public class SingletonClientMultiChannelFactory {

    public Channel channel;

    // 获取唯一的 channel 对象
    public Channel getChannel() throws InterruptedException {
        return this.channel;
    }

    // 初始化 channel 方法
    public void startClientChannel(String address,String port) throws InterruptedException {

        NioEventLoopGroup group = new NioEventLoopGroup();
        LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
        MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
        RpcResponseMessageHandler RPC_HANDLER = new RpcResponseMessageHandler();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.group(group);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new ProcotolFrameDecoder());
                ch.pipeline().addLast(LOGGING_HANDLER);
                ch.pipeline().addLast(MESSAGE_CODEC);
                ch.pipeline().addLast(RPC_HANDLER);
            }
        });
        try {

            channel = bootstrap.connect(address, Integer.parseInt(port)).sync().channel();

            //主机强迫关闭有pineline所报的异常只会触发closeFuture,connect不会触发异常,因此需要在future中重新断联重试
            channel.closeFuture().addListener(future -> {
                log.error("client closefuture {}", channel);
                TimeUnit.SECONDS.sleep(3);
                //断联重试
                this.startClientChannel(address,port);
            });
        } catch (Exception e) {
            log.error("client error {}", e.getMessage());
            TimeUnit.SECONDS.sleep(3);
            //断联重试
            this.startClientChannel(address,port);
        }



    }

}
